//
// Created by DELL on 2024/7/22.
//

#include <iostream>
#include <random>
#include <coroutine>

// 视频教程地址
// https://www.bilibili.com/video/BV1c8411f7dw

// Suspend(false) -> std::suspend_never
// Suspend(true) -> std::suspend_always

struct CoRet
{
    struct promise_type
    {
        int num{-1};
        int result{-1};
        int guessCount{-1};

        // 进入协程函数时会调用，这个值会存放在堆中，直到整个协程调用destroy才会释放
        CoRet get_return_object()
        {
//            std::cout << "CoRet::promise_type::get_return_object" << std::endl;
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }

        // 协程开始时调用
        std::suspend_never initial_suspend() noexcept
        {
//            std::cout << "CoRet::promise_type::initial_suspend" << std::endl;
            return {};
        }

        // 协程函数结束时调用
        // Suspend(true) 表示协程结束后保留结果，后续不能调用resume，
        // Suspend(false)表示会销毁整个协程
        std::suspend_always final_suspend() noexcept
        {
            return {};
        }

        std::suspend_always yield_value(int r) noexcept
        {
            result = r;
            return {};;
        }

        // return_value 和 return_void 只能有一个
        void return_value(int count)
        {
            guessCount = count;
        }

//        void return_void()
//        {
//            std::cout << "CoRet::promise_type::return_void" << std::endl;
//        }

        void unhandled_exception()
        {
            std::cout << "CoRet::promise_type::unhandled_exception" << std::endl;
        }
    };

    std::coroutine_handle<promise_type> handle;
};

struct Input
{
    CoRet::promise_type* promise{};

    bool await_ready()
    {
        std::cout << "Input::await_ready, ready: false" << std::endl;
        // false 代表 co_await 要暂停，返回到 await_suspend 指定的执行位置
        // true 代表 co_await 不需要暂停 继续执行
        return false;
    }

    void await_suspend(const std::coroutine_handle<CoRet::promise_type>& handle)
    {
        std::cout << "Input::await_suspend" << std::endl;

        // 返回void表示返回到调用者，这里代表 main 函数
        // 返回其他的 coroutine_handle 则会执行对应的携程

        promise = &handle.promise();
    }

    int await_resume()
    {
        std::cout << "Input::await_resume" << std::endl;

        // 返回对应 co_await 的返回
        return promise->num;
    }

};

CoRet Guess()
{
    // 携程函数启动时，会有以下操作
//    CoRet::promise_type promise;
//    CoRet ret = promise.get_return_object();
//    co_await promise.initial_suspend();

    std::cout << "Guess: Start" << std::endl;
    std::random_device rd;
    std::default_random_engine randomEngine{rd()};
    std::uniform_int_distribution<> distr(0,30);
    int res = distr(randomEngine);

    Input input;
    int g = co_await input;

    int guessCount{0};
    while (true)
    {
        g = input.promise->num;

        std::cout << "Guess: number: " << g << std::endl;
        ++guessCount;

        if (g == res)
        {
            input.promise->result = 0;
            co_return guessCount;
        }
        else if (g > res)
        {
            co_yield 1;
        }
        else
        {
            co_yield -1;
        }
    }
}


int main()
{
    auto ret = Guess();

    int left = 0;
    int right = 30;

    while (!ret.handle.done())
    {
        ret.handle.promise().num = (left + right) / 2;
        ret.handle.resume(); // resume form co_await

        auto result = ret.handle.promise().result;
        if (result > 0)
        {
            right = ret.handle.promise().num - 1;
        }
        else if (result < 0)
        {
            left = ret.handle.promise().num + 1;
        }
    }

    std::cout << "Main: done, number:" << ret.handle.promise().num
              << ",  guess count:" << ret.handle.promise().guessCount << std::endl;


    // 手动销毁数据，销毁后不能在获取携程的运行结果
//    ret._h.destroy();

    return 0;
}